import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;
import org.apache.catalina.Session;
import org.apache.catalina.SessionEvent;

import com.google.gson.Gson;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Random;

public class AsyncServlet extends HttpServlet implements CometProcessor {

	public void event(CometEvent event) throws IOException, ServletException {
		HttpServletRequest request = event.getHttpServletRequest();
		HttpServletResponse response = event.getHttpServletResponse();
		if (event.getEventType() == CometEvent.EventType.BEGIN) {
			try {
				begin(event, request, response);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		} else if (event.getEventType() == CometEvent.EventType.ERROR) {
			error(event, request, response);
		} else if (event.getEventType() == CometEvent.EventType.END) {
			end(event, request, response);
		} else if (event.getEventType() == CometEvent.EventType.READ) {
			read(event, request, response);
		}
	}

	protected void begin(CometEvent event, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException,
			SQLException {

		HttpSession session = request.getSession();
		int gameId = (Integer) session.getAttribute("gameID");
		String data = request.getParameter("info");

		ArrayList<Game> gamesArray = GamesHandler.games;
		Game currentGame = null;
		for (int i = 0; i < gamesArray.size(); i++) {
			if (gamesArray.get(i).getId() == gameId) {
				currentGame = gamesArray.get(i);
				break;
			}
		}
		String username = (String) session.getAttribute("username");
		response.setContentType("application/json");

		try{
			if (username.equals(currentGame.getPl1())) {
				currentGame.setPl1Response(response);
			} else if (username.equals(currentGame.getPl2())) {
				currentGame.setPl2Response(response);

			}


			if (data.equals("null")) {

				if (username.equals(currentGame.getPl1())) {
					currentGame.setPlayer1Event(event);		
				} else if (username.equals(currentGame.getPl2())) {
					currentGame.setPlayer2Event(event);
				}


				if (currentGame.getPl1Response() != null
						&& currentGame.getPl2Response() != null) {
					if (!currentGame.turnDecided) {
						synchronized (currentGame) {
							if (decideTurn(currentGame)) {
								currentGame.getPl1Response().getWriter()
								.write("start"+currentGame.getPl2()+","+currentGame.getPl1());
								currentGame.getPl2Response().getWriter().write("name="+
										currentGame.getPl1()+","+currentGame.getPl2());
								currentGame.getPlayer2Event().close();
							} else {
								currentGame.getPl2Response().getWriter()
								.write("start"+currentGame.getPl1()+","+currentGame.getPl2());
								currentGame.getPl1Response().getWriter().write("name="+
										currentGame.getPl2()+","+currentGame.getPl1());
								currentGame.getPlayer1Event().close();
							}
						}
						event.close();
					}

				}
			}

			else {

				if (currentGame.getPl1Response() != null
						&& currentGame.getPl2Response() != null) {
					String correctShipID = data.replace("enemy", "").toLowerCase();

					if (username.equals(currentGame.getPl1())) {


						Ship beingHit = currentGame.strike(correctShipID, true);

						Response jsonResponseObj;
						if (beingHit != null) {

							if (beingHit.getHealth() == 0) {
								jsonResponseObj = new Response(true,
										beingHit.getHealth(),
										beingHit.isDirection(),
										beingHit.getCoordinates()[0],
										beingHit.getCoordinates().length,
										currentGame.winnerCheck() != null);
							} else {
								jsonResponseObj = new Response(true,
										beingHit.getHealth(),
										beingHit.isDirection(), correctShipID,
										beingHit.getCoordinates().length,
										currentGame.winnerCheck() != null);
							}

						} else {
							jsonResponseObj = new Response(false, -1, false,
									correctShipID, -1, false);

						}

						Gson gson = new Gson();

						String jsonResponse = gson.toJson(jsonResponseObj);
						synchronized (currentGame) {
							response.getWriter().write(jsonResponse);
							currentGame.getPl2Response().getWriter()
							.write(correctShipID);
							currentGame.getPlayer2Event().close();
							currentGame.getPlayer1Event().close();
						}

						if (currentGame.winnerCheck() != null) {
							EndGame.writeResultsToDB(currentGame.getPl1(),
									currentGame.getPl2(), currentGame.winnerCheck());
							GamesHandler.games.remove(currentGame);
						}
						event.close();

					} else {



						Ship beingHit = currentGame.strike(correctShipID, false);

						Response jsonResponseObj;
						if (beingHit != null) {

							if (beingHit.getHealth() == 0) {
								jsonResponseObj = new Response(true,
										beingHit.getHealth(),
										beingHit.isDirection(),
										beingHit.getCoordinates()[0],
										beingHit.getCoordinates().length,
										currentGame.winnerCheck() != null);
							} else {
								jsonResponseObj = new Response(true,
										beingHit.getHealth(),
										beingHit.isDirection(), correctShipID,
										beingHit.getCoordinates().length,
										currentGame.winnerCheck() != null);
							}

						} else {
							jsonResponseObj = new Response(false, -1, false,
									correctShipID, -1, false);

						}

						Gson gson = new Gson();

						String jsonResponse = gson.toJson(jsonResponseObj);
						synchronized (currentGame) {
							response.getWriter().write(jsonResponse);
							currentGame.getPl1Response().getWriter()
							.write(correctShipID);
							currentGame.getPlayer2Event().close();
							currentGame.getPlayer1Event().close();
						}

						if (currentGame.winnerCheck() != null) {
							EndGame.writeResultsToDB(currentGame.getPl1(),
									currentGame.getPl2(), currentGame.winnerCheck());
							GamesHandler.games.remove(currentGame);
						}
						event.close();

					}
				}

			}
		}catch (NullPointerException e) {
			PrintWriter out = response.getWriter();
			out.print("error");
			out.flush();
			event.close();
			try {
				finalize();
			} catch (Throwable e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

	}

	private boolean decideTurn(Game game) {
		Random rnd = new Random();
		int a = rnd.nextInt(2);
		game.setTurn(true);
		if (a == 0) {
			return true;
		} else {
			return false;
		}

	}

	protected void end(CometEvent event, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException {
		//log("End for session: " + request.getSession(true).getId());
		event.close();
	}

	protected void error(CometEvent event, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException {
		// log("Error for session: " + request.getSession(true).getId());

		HttpSession session = request.getSession();
		int gameId = (Integer) session.getAttribute("gameID");

		ArrayList<Game> gamesArray = GamesHandler.games;
		Game currentGame = null;
		for (int i = 0; i < gamesArray.size(); i++) {
			if (gamesArray.get(i).getId() == gameId) {
				currentGame = gamesArray.get(i);
				break;
			}
		}
		String username = (String) session.getAttribute("username");
		try{
			synchronized (currentGame) {
				if (username.equals(currentGame.getPl1())) {
					currentGame.setPl1Response(null);
				} else if (username.equals(currentGame.getPl2())) {
					currentGame.setPl2Response(null);
				}
			}
		}catch (NullPointerException e) {
			// TODO: handle exception
		}

		event.close();
	}

	protected void read(CometEvent event, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException {

	}
}